////////////////////////////////////////////////////////////////////////////////
// ps2spu - SPU2 emulator for Pcsx2.
// Copyright (C) 2007 ps2spu team
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
////////////////////////////////////////////////////////////////////////////////

#include "SpuEssentials.hpp"
#include "SpuMemory.hpp"
#include "SpuLog.hpp"
#include "SpuRegisters.hpp"
using namespace ps2spu;

//! \brief Standard return values for plugin functions
enum EnumInterfaceResult
{
    EIR_SUCCESS = 0,
    EIR_FAILURE = -1
};

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

void (*ps2spu::SPU2_CALLBACK_PTR)(void) = NULL;
void (*ps2spu::DMA4_CALLBACK_PTR)(void) = NULL;
void (*ps2spu::DMA7_CALLBACK_PTR)(void) = NULL;

////////////////////////////////////////////////////////////////////////////////
// Library Entry Point
////////////////////////////////////////////////////////////////////////////////

#ifdef PS2SPU_WINDOWS
    BOOL APIENTRY DllMain(HANDLE module_handle, DWORD reason, LPVOID)
    {
        if(reason == DLL_PROCESS_ATTACH)
        {
            ps2spu::MODULE_HANDLE = static_cast<HINSTANCE>(module_handle);
            ps2spu::WINDOW_HANDLE = ::GetActiveWindow();
        }

        return TRUE;
    }
#else
#endif

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

u32 CALLBACK PS2EgetLibType()
{
    return PS2E_LT_SPU2;
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

u32 CALLBACK PS2EgetLibVersion2(u32)
{
    return MAKE_PS2E_VERSION(PS2SPU_VERSION_MAJOR, PS2SPU_VERSION_MINOR);
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

char* CALLBACK PS2EgetLibName()
{
    return const_cast<char*>(PS2SPU_LIBRARY_NAME);
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

//! \brief Do any initialization not used for actually SPU2 emulation
s32 CALLBACK SPU2init()
{
    return EIR_SUCCESS;
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

//! \brief Completely shutdown the plugin and destroy everything
void CALLBACK SPU2shutdown()
{
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

//! \brief Initialize all emulation critical systems
s32 CALLBACK SPU2open(void* dsp_ptr)
{
    return EIR_SUCCESS;
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

//! \brief Close any emulation critical systems
void CALLBACK SPU2close()
{
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

//! \brief Write 16bits of data into memory
void CALLBACK SPU2write(u32 address, u16 value)
{
    try
    {
        memory::write(address, value);
    }
    catch(std::exception& e)
    {
        LOG_FMT("Failed write @ 0x%05x: %s", address, e.what());
    }
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

//! \brief Read 16bits of data from memory
u16 CALLBACK SPU2read(u32 address)
{
    try
    {
        return memory::read(address);
    }
    catch(std::exception& e)
    {
        LOG_FMT("Failed read @ 0x%05x: %s", address, e.what());
        return 0;
    }
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

//! \brief Read data from memory using DMA4 access
void CALLBACK SPU2readDMA4Mem(u16* mem_ptr, int size)
{
    try
    {
        memory::read(SPU2_TSA, mem_ptr, size);
    }
    catch(std::exception& e)
    {
        LOG_FMT("Failed DMA4 read @ 0x%05x: %s", SPU2_TSA, e.what());
    }
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

//! \brief Write data to memory using DMA4 access
void CALLBACK SPU2writeDMA4Mem(u16* mem_ptr, int size)
{
    try
    {
        memory::write(SPU2_TSA, mem_ptr, size);
    }
    catch(std::exception& e)
    {
        LOG_FMT("Failed DMA4 write @ 0x%05x: %s", SPU2_TSA, e.what());
    }
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

//! \brief Trigger a DMA4 interrupt
void CALLBACK SPU2interruptDMA4()
{
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

//! \brief Read data from memory using DMA7 access
void CALLBACK SPU2readDMA7Mem(u16* mem_ptr, int size)
{
    try
    {
        memory::read(SPU2_TSA, mem_ptr, size);
    }
    catch(std::exception& e)
    {
        LOG_FMT("Failed DMA7 read @ 0x%05x: %s", SPU2_TSA, e.what());
    }
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

//! \brief Write data to memory using DMA7 access
void CALLBACK SPU2writeDMA7Mem(u16* mem_ptr, int size)
{
    try
    {
        memory::write(SPU2_TSA, mem_ptr, size);
    }
    catch(std::exception& e)
    {
        LOG_FMT("Failed DMA7 write @ 0x%05x: %s", SPU2_TSA, e.what());
    }
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

//! \brief Trigger a DMA7 interrupt
void CALLBACK SPU2interruptDMA7()
{
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

void CALLBACK SPU2setDMABaseAddr(uptr base_addr)
{
    SPU2_TSA = base_addr & 0x00FFFFFF;
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

u32 CALLBACK SPU2ReadMemAddr(int core)
{
    return 0;
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

void CALLBACK SPU2WriteMemAddr(int core, u32 value)
{
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

void CALLBACK SPU2irqCallback(void (*SPU2callback)(void),
                              void (*DMA4callback)(void),
                              void (*DMA7callback)(void))
{
    ps2spu::SPU2_CALLBACK_PTR = SPU2callback;
    ps2spu::DMA4_CALLBACK_PTR = DMA4callback;
    ps2spu::DMA7_CALLBACK_PTR = DMA7callback;
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

void CALLBACK SPU2async(u32 cycles)
{
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

s32 CALLBACK SPU2freeze(int mode, freezeData* freeze_data_ptr)
{
    return EIR_FAILURE;
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

void CALLBACK SPU2configure()
{
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

void CALLBACK SPU2about()
{
}

////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////

s32 CALLBACK SPU2test()
{
    return EIR_SUCCESS;
}